package test.threads.queue.stressed.memory;

import java.util.Arrays;

import net.jcip.annotations.Immutable;
import net.jcip.annotations.NotThreadSafe;
import test.helpers.Config;
import test.threads.queue.common.IUsefulWorkEmulator;
import test.threads.queue.common.IUsefulWorkFactory;

import static com.google.common.base.Preconditions.checkArgument;

/**
 * @author cheremin
 * @since 02.03.12,  15:41
 */
@NotThreadSafe
public class MemoryWasterFactory implements IUsefulWorkFactory<LongArrayMessage> {

    private final int opsPerPacket;

    public MemoryWasterFactory( final Config config ) {
        opsPerPacket = config.getAsInt( "payload.ops-per-packet" );
    }

    private int operationsPerNode = -1;

    @Override
    public IUsefulWorkEmulator<LongArrayMessage>[] createEmulators( final int count ) {
        checkArgument( opsPerPacket % count == 0, "opsPerPacket(%s) % workerCount(%s) must be 0", opsPerPacket, count );
        operationsPerNode = opsPerPacket / count;

        final IUsefulWorkEmulator<LongArrayMessage>[] emulators = new IUsefulWorkEmulator[count];

        final MemoryTimeWaster accessTimeWaster = new MemoryTimeWaster();
        Arrays.fill( emulators, accessTimeWaster );

        return emulators;
    }

    private long index = 0;

    @Override
    public LongArrayMessage newInstance() {
        final long[] longs = new long[operationsPerNode];
        longs[0] = index++;
//        for ( int i = 0; i < longs.length; i++ ) {
//            longs[i] = index++;
//        }
        return new LongArrayMessage( longs );
    }

    @Override
    public String toString() {
        return "memory["+ operationsPerNode +" ops/node]";
    }

    /**
     * Just simple mul/add -- only consume CPU cycles
     *
     * @author cheremin
     * @since 27.02.12,  13:42
     */
    @Immutable
    private static class MemoryTimeWaster implements IUsefulWorkEmulator<LongArrayMessage> {
        /** 64 byte => 8 longs */
        private static final long CACHE_LINE_SIZE = 8;

        @Override
        public long spendCPUTime( final LongArrayMessage message ) {
            final long[] array = message.array;
            long result = 1;
            //trying to do as few CPU work as possible, but be sure all array content
            // is actually accessed
            for ( int i = 0; i < array.length; i += CACHE_LINE_SIZE ) {
                result ^= array[i] + 42;
                array[i] = result;
            }
            return result;
        }
    }
}
